﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CardCharger.lib;

namespace CardCharger.lib
{



    /// <summary>
    /// file信息结构体
    /// </summary>
    public class DFInfo{


#region  常量
        public const byte FT_DF = 0;
        public const byte FT_EF = 1;
#endregion

#region  static 函数
    static byte[] GetNumberBytes(byte[] src,int offset,int len){

        if (src == null) return null;
        byte[] _re = new byte[len];
        Array.Copy(src, offset, _re, 0, len);
        return _re;
    }

#endregion

    byte[] _data = new byte[16];

#region 变量
        public byte[] FileId
        {
            get { return GetNumberBytes(_data, 0, 2); }
            set { Array.Copy(value, 0, _data, 0, value.Length); }
        }
        public byte FildType { get { return _data[2]; } set { _data[2] = value; } }
        public byte[] FileInfo { 
            get { return GetNumberBytes(_data, 3, _data.Length - 3); }
            set { Array.Copy(value, 0, _data, 3, value.Length); }
        }

#endregion

        public DFInfo() { }

        public DFInfo(byte[] _src)
        {
            if (_data.Length != _src.Length) _data = new byte[_src.Length];
            Array.Copy(_src, _data, (_src.Length > _data.Length) ? _data.Length : _src.Length);
        }
    };



    public class KeyInfo{

 #region  static 函数
    static byte[] GetNumberBytes(byte[] src,int offset,int len){

        if (src == null) return null;
        byte[] _re = new byte[len];
        Array.Copy(src, offset, _re, 0, len);
        return _re;
    }

#endregion


        byte[] _data = new byte[21];

        /// <summary>
        /// 信息//密钥信息: 密钥类型 使用权 更改权 后续状态 错误计数器 等
        /// </summary>
        public byte[] Info{
            get{return GetNumberBytes(_data,0,5);}
            set{Array.Copy(value,0,_data,0,value.Length);}
        }

        
        /// <summary>
        /// //密钥
        /// </summary>
        public byte[] Key{
            get{return GetNumberBytes(_data,5,16);}
            set{Array.Copy(value,0,_data,5,value.Length);}
        }

        public KeyInfo(){}
        public KeyInfo(byte[] _src)
        {
                        Array.Copy(_src, _data, (_src.Length > _data.Length) ? _data.Length : _src.Length);
        }


        public byte[] ToBytes() { return _data; }

        }

    /// <summary>
    ///  发卡操作类
    ///  cpu 卡，文件操作
    /// </summary>
    public class UserCardIssue
    {


        #region 接口
        public CardOS cardos;
        #endregion

        #region 文件信息
        /// <summary>
        /// 根目录文件id
        /// </summary>
        const UInt16 MFFileId = 0x3F00;


        //////////////////////////////////////////////////////////////////////////
        ///文件信息
        /// <summary>
        /// 根目录下DF文件id
        /// </summary>
        static UInt16 DFFildId = 0x1A00;
        readonly DFInfo DFFile = new DFInfo(new byte[]{
            0x1A,0x00, //文件ID
            DFInfo.FT_DF, //文件类型
            0x38,0x03,0x30,0xF0,0xF0,0xFF,0xFF,0xFF,0x50,0x50,0x50,0x50,0x50 //文件信息
        });

        
        /// <summary>
        /// //售电文件信息
        /// </summary>
        static UInt16 ShouDianFileId = 0x0201;
        readonly DFInfo ShouDianFile = new DFInfo(new byte[] {
            0x02,0x01, //文件ID
            DFInfo.FT_EF, //文件类型
            0x28,0x01,0x00,0xF1,0xF4,0xFF,0xFF//文件信息
        });


        /// <summary>
        /// 卡内部记录内容结构体
        /// </summary>
        public class t_GCZ_CardInfo {
            public UInt64 CardID;  //卡号
            public UInt64 Key;     //密码
            public UInt32 Sum;      //充电卡余额
            public byte Lock;      //锁卡标志
            public UInt64 PileAddr; //桩地址
            public byte GunNum;    //枪号

            public byte[] toBytes() {

                byte[] bytes = new byte[30];

                Ulitily.ShareClass.UInt64ToBytes(CardID, bytes, 0, 0);
                Ulitily.ShareClass.UInt64ToBytes(Key, bytes, 8, 0);
                Ulitily.ShareClass.UInt32ToBytes(Sum,bytes, 16, 0);
                bytes[20] = Lock;
                Ulitily.ShareClass.UInt64ToBytes(PileAddr, bytes, 21, 0);
                bytes[29] = GunNum;
                return bytes;
            }


            /// <summary>
            /// default
            /// </summary>
            public t_GCZ_CardInfo()
            {
                this.CardID = 0x0000000100000002;
                this.Key = 0;
                this.Sum = 0;
                this.Lock = 0; //0 unlock   1:locked
                this.PileAddr = 0;
                this.GunNum = 0;
            }

            public t_GCZ_CardInfo(byte[] data) {

                Ulitily.ShareClass.BytesToUInt64(ref CardID, data, 0, 0);
                Ulitily.ShareClass.BytesToUInt64(ref Key, data, 8, 0);
                Ulitily.ShareClass.BytesToUInt32(ref Sum, data, 16, 0);
                Lock = data[20];
                Ulitily.ShareClass.BytesToUInt64(ref PileAddr, data, 21, 0);
                GunNum = data[29];
            }


            /// <summary>
            /// 比较
            /// </summary>
            /// <param name="c"></param>
            /// <returns></returns>
            public bool Equal(t_GCZ_CardInfo c) {

                if (CardID == c.CardID && Key == c.Key && Sum == c.Sum && Lock == c.Lock && PileAddr == c.PileAddr && GunNum == c.GunNum) return true;
                else return false;
            }
        }

        
        /// <summary>
        /// //预留的充电记录文件信息
        /// </summary>
        static UInt16 ChargeReFileId = 0x0202;
        readonly DFInfo  ChargeReFile = new DFInfo(new byte[] {
            0x02,0x02, //文件ID
            DFInfo.FT_EF, // 文件类型
            0x28,0x01,0x00,0xF1,0xF3,0xFF,0xFF //文件信息
        });

        static UInt16 KeyFildId = 0x0000;
        readonly DFInfo KeyFile = new DFInfo(new byte[] {
            0x00,0x00, //文件ID
            DFInfo.FT_EF, // 文件类型
            0x3F,0x01,0x00,0xFF,0xF0,0xFF,0xFF //文件信息
        });

        #endregion

        #region ＫＥＹ　信息
        //////////////////////////////////////////////////////////////////////////
        /// Key 信息
        /// MF 的key   MF的Key信息(主目录外部认证密钥key 0，没使用SN分散密钥)	
        readonly KeyInfo MfKey = new KeyInfo(
            new byte[]{
                0x39, 0xF0, 0xF7, 0x0A, 0xFF, //密钥信息
                0xB9,0xE3,0xD6,0xDD,0xB8,0xDF,0xCC,0xEC,0xB5,0xE7,0xC1,0xA6,0xBF,0xC6,0xBC,0xBC//密钥
            });

        /// //未初始化过的卡，默认外部认证密钥为全FF
        readonly KeyInfo InitKey = new KeyInfo(
            new byte[]{
                0x00, 0x00, 0x00,0x00,0x00, //密钥信息
                0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF//密钥
            });

        /// 全 0 key
        readonly KeyInfo NullKey = new KeyInfo(
            new byte[]{
                0x00, 0x00, 0x00,0x00,0x00, //密钥信息
                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0//密钥
            });

        /// DF 的key
        readonly KeyInfo DfKey = new KeyInfo(
            new byte[]{
                0x39, 0xF0, 0xF7, 0x04, 0xFF, //密钥信息
                0xE8,0x3F,0xED,0x14,0x59,0x52,0x12,0x3B,0x5C,0x14,0xEC,0x4E,0x9F,0x8D,0x86,0xF0//密钥
            });


        #endregion


        #region 构造，设备接口 ICardReader为 入参
        public UserCardIssue(CardOS cos)
        {
            cardos = cos;
        }
        #endregion


        #region  发卡


        #region 卡操作


        /// <summary>
        /// 读售电信息，返回数据
        /// </summary>
        /// <returns></returns>
        t_GCZ_CardInfo ReadCardShouDian()
        {
            byte[] rbuffer = new byte[30];
            Array.Clear(rbuffer, 0, rbuffer.Length);
            int rlen = 0;
            if ((rlen = cardos.CardReadBInFile(ShouDianFileId, 0, rbuffer, (byte)rbuffer.Length)) < 0) { Console.WriteLine("读取 售电文件 失败."); return null; }
            else
            {
                if (rlen < 30) return null;
                t_GCZ_CardInfo cardinfo = new t_GCZ_CardInfo(rbuffer);
                return cardinfo;
            }
        }

        /// <summary>
        /// 写售电信息，返回是否成功
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        bool WriteCardShouDian(t_GCZ_CardInfo info) {
            byte[] buffer = info.toBytes();
            if (cardos.CardWriteBinFile(ShouDianFileId, 0, buffer, (byte)buffer.Length) == false) { Console.WriteLine("写 售电信息 出错。"); return false; }
            else { Console.WriteLine("已经 成功  写入 售电信息."); return true; }
        }
        #endregion



        public event Ulitily.LogEventHandler Issueloghandler;   //发卡
        public event Ulitily.LogEventHandler Rechargeloghandler;//充值

        public void Log(object sender, string msgType, string msglog, string options,Ulitily.LogEventHandler handle) {
            if (handle != null) handle(sender, msgType, msglog, options);
        }

       
       


        //检查认证卡
        /// <summary>
        /// 检查卡存在
        /// </summary>
        /// <param name="cardid">输出变量：卡id</param>
        /// <returns> 0 ：succeed  ,其它：error</returns>
        public int CheckCard(byte[] _cardid)
        {
            int errorcode = 0;
            byte[] cardid =  cardos.icardReader.CardGetId();
            if (cardid == null) {return -1;}
            Array.Copy(cardid, _cardid, 8);

            /////////////////////////////////////////////////////////////
            //选择MF
            if (cardos.CardSelectFile(MFFileId) == false)
            {
                Console.WriteLine("选择 MF 文件失败.");
                errorcode = -2; goto CHECK_ERROR;
            }
            else { Console.WriteLine("选择 MF 文件 ok"); }

            //////////////////////////////////////////////////////////////
            /////认证
            if (cardos.CardExternalAuthenticate(
                cardid, 0, MfKey.Key, false) == false)
            {

                if (cardos.CardExternalAuthenticate(
                    cardid, 0, InitKey.Key, false) == false)
                {
                    Console.WriteLine("外部认证不过,init key.");
                    errorcode = -3; goto CHECK_ERROR;
                }
                else { Console.WriteLine("init key 认证 通过."); }
            }
            else
            {
                Console.WriteLine("MF key 认证通过");
            }

            return 0;

            CHECK_ERROR:
            return errorcode;
        }


        //发卡
        public  bool Issue(t_GCZ_CardInfo cardInfo)
        {
            int errorcode = 0;
            byte[] cardid = new byte[8];
            if ((errorcode = CheckCard(cardid)) != 0) { 
                string estring = errorcode==-1?"没有找到卡":"检测卡错误";
                Log(this, "error", estring + errorcode, null, Issueloghandler);
                goto ISSUE_ERROR;
            }

            //////////////////////////////////////////////////////////
            //删除MF子文件
            if (cardos.CardDeleteDF() == false) {  Console.WriteLine("删除MF下目录文件出错."); errorcode = -3; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经清空 MF 下 所有文件."); }

            //////////////////////////////////////////////////////////
            //创建MF key文件
            if (cardos.CardCreateFile(KeyFile) == false) { Console.WriteLine("MF 下 新建 keyfile 出错."); errorcode = -4; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经在MF下新建 key file."); }
            //写key
            if (cardos.CardWriteKey(0, MfKey) == false) { Console.WriteLine("MF 下 写入 keyfile 出错."); errorcode = -5; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经在MF下 写入key file."); }

            //创建DF 文件
            if (cardos.CardCreateFile(DFFile) == false) { Console.WriteLine("MF 下 新建 DF 出错."); errorcode = -6; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经在MF下新建 DF ."); }
            if (cardos.CardSelectFile(DFFildId) == false) { Console.WriteLine("选择DF 出错."); errorcode = -7; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经选择 DF."); }

            //创建DF key文件
            if (cardos.CardCreateFile(KeyFile) == false) { Console.WriteLine("DF 下 新建 keyfile 出错."); errorcode = -8; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经在DF下新建 key file."); }
            //分散了密钥
            KeyInfo tmp = new KeyInfo(DfKey.ToBytes());
            byte[] tmpkey = new byte[16];
            ThreeDes.Diversify(DfKey.Key, cardid, tmpkey);  //tmp.Key 不能被看作一个数据作为入参
            tmp.Key = tmpkey;

            //写key
            if (cardos.CardWriteKey(4, tmp) == false) { Console.WriteLine("DF 下 写入 keyfile 出错."); errorcode = -9; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经在DF下 写入key file."); }

            //认证一下当然的 key
            if (cardos.CardExternalAuthenticate(cardid, 4, DfKey.Key, true) == false) { Console.WriteLine(" DF 下 key 认证出错."); errorcode = -10; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经 在DF 下的 key 4 认证通过."); }

            //新建 售电 文件
            //创建MF key文件
            if (cardos.CardCreateFile(ShouDianFile) == false) { Console.WriteLine("DF 下 新建 售电文件 出错."); errorcode = -11; goto ISSUE_ERROR; }
            else { Console.WriteLine("已经在DF下新建  售电文件 ."); }

            //写入 售电信息
           // t_GCZ_CardInfo cardInfo = new t_GCZ_CardInfo();
            if (WriteCardShouDian(cardInfo) == false) {
                errorcode = -12;
                goto ISSUE_ERROR;
            }
            //读出售电信息，比较 是否成功
            t_GCZ_CardInfo rcardInfo = ReadCardShouDian();
            if (rcardInfo == null) { errorcode = -13; goto ISSUE_ERROR; }
            else {
                if (rcardInfo.Equal(cardInfo))
                {
                    cardos.icardReader.CardReaderCtrl(new String[] { "Buzzer", "2" });
                    cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
                    Log(this, "msg", "发卡成功", null, Issueloghandler);
                    string msg = string.Format("CardId:{0:X16}\r\nKey:{1:X16}\r\nLock:{2}\r\nGun:{3:X2}\r\nAddr:{4:X16}\r\nSum:{5:C}", cardInfo.CardID, cardInfo.Key, cardInfo.Lock, cardInfo.GunNum, cardInfo.PileAddr, ((double)(cardInfo.Sum)) / 100);
                    Log(this, "", msg, null, Issueloghandler);        
                    return true;
                }
                else { errorcode = -14; goto ISSUE_ERROR; }
            }


            ISSUE_ERROR:
            Log(this, "error", "发卡失败" + errorcode, null, Issueloghandler);
            cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
            return false;
        }


        //充值 dec==true:减去   dec==false:增加     momey ＝＝实际金额 *100
        public bool ChargeValue(UInt32 money, bool dec)
        { 
            // 认证
            int errorcode = 0;
            byte[] cardid = new byte[8];
            if ((errorcode = CheckCard(cardid)) != 0)
            {
                string estring = errorcode == -1 ? "没有找到卡" : "检测卡错误";
                Log(this, "error", estring + errorcode, null, Rechargeloghandler);
                goto ChargeValue_Error;
            }
            //进入DF
            if (cardos.CardSelectFile(DFFildId) != true) { errorcode = -2; goto ChargeValue_Error; }


            //认证
            if (cardos.CardExternalAuthenticate(cardid, 4, DfKey.Key, true) == false) { Console.WriteLine(" DF 下 key 认证出错."); errorcode = -3; goto ChargeValue_Error; }
            else { Console.WriteLine("已经 在DF 下的 key 4 认证通过."); }

            //读卡
            t_GCZ_CardInfo cardInfo = ReadCardShouDian();
            if (cardInfo == null) { errorcode = -4; goto ChargeValue_Error; }

            //金额计算
            UInt32 m = money;
            if (dec == true) { if (cardInfo.Sum < m) { cardInfo.Sum = 0; } else cardInfo.Sum -= m; }
            else {
                cardInfo.Sum += m;
            }

            //写卡
            if (WriteCardShouDian(cardInfo) == false){errorcode = -5;goto ChargeValue_Error;}
            //再读检查
            //读出售电信息，比较 是否成功
            t_GCZ_CardInfo rcardInfo = ReadCardShouDian();
            if (rcardInfo == null) { errorcode = -13; goto ChargeValue_Error; }
            else
            {
                if (rcardInfo.Equal(cardInfo))
                {
                    cardos.icardReader.CardReaderCtrl(new String[] { "Buzzer", "1" });
                    cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
                    Log(this, "msg", "充值成功", null, Rechargeloghandler);
                    string msg = string.Format("CardId:{0:X16}\r\nKey:{1:X16}\r\nLock:{2}\r\nGun:{3:X2}\r\nAddr:{4:X16}\r\nSum:{5:C}", cardInfo.CardID, cardInfo.Key, cardInfo.Lock, cardInfo.GunNum, cardInfo.PileAddr, ((double)(cardInfo.Sum)) / 100);
                    Log(this, "", msg, null, Rechargeloghandler);  
                    return true;
                }
                else { errorcode = -14; goto ChargeValue_Error; }
            }


            ChargeValue_Error:
            Log(this, "error", "充值失败" + errorcode, null, Rechargeloghandler);
            cardos.icardReader.CardReaderCtrl(new string[] { "Antenna","off" });
            return false;
        }


        /// <summary>
        /// 读售电卡信息
        /// </summary>
        /// <returns></returns>
        public bool ReadShouDian()
        {
            // 认证
            int errorcode = 0;
            byte[] cardid = new byte[8];
            if ((errorcode = CheckCard(cardid)) != 0)
            {
                string estring = errorcode == -1 ? "没有找到卡" : "检测卡错误";
                Log(this, "error", estring + errorcode, null, Rechargeloghandler);
                goto ReadShouDian_Error;
            }

            //进入DF
            if (cardos.CardSelectFile(DFFildId) != true) { errorcode = -2; goto ReadShouDian_Error; }

            //认证
            if (cardos.CardExternalAuthenticate(cardid, 4, DfKey.Key, true) == false) { Console.WriteLine(" DF 下 key 认证出错."); errorcode = -3; goto ReadShouDian_Error; }
            else { Console.WriteLine("已经 在DF 下的 key 4 认证通过."); }

            //读卡
            t_GCZ_CardInfo cardInfo = ReadCardShouDian();
            if (cardInfo == null) { errorcode = -4; goto ReadShouDian_Error; }

            //显示卡的数据
            string msg = string.Format("CardId:{0:X16}\r\nKey:{1:X16}\r\nLock:{2}\r\nGun:{3:X2}\r\nAddr:{4:X16}\r\nSum:{5:C}", cardInfo.CardID, cardInfo.Key, cardInfo.Lock,cardInfo.GunNum, cardInfo.PileAddr, ((double)(cardInfo.Sum)) / 100);
            Log(this, "", msg, null, Rechargeloghandler);
            cardos.icardReader.CardReaderCtrl(new String[] { "Buzzer", "2" });
            cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
            return true;

            ReadShouDian_Error:
            Log(this, "error", "读卡失败" + errorcode, null,Rechargeloghandler);
            cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
            return false;
        }
        

        /// <summary>
        /// 设置锁
        /// </summary>
        /// <param name="lockSet">true:锁定， flase</param>
        /// <returns></returns>
        public bool LockCard(bool lockSet)
        {
            // 认证
            int errorcode = 0;
            byte[] cardid = new byte[8];
            if ((errorcode = CheckCard(cardid)) != 0)
            {
                string estring = errorcode == -1 ? "没有找到卡" : "检测卡错误";
                Log(this, "error", estring + errorcode, null, Rechargeloghandler);
                goto ChargeValue_Error;
            }
            //进入DF
            if (cardos.CardSelectFile(DFFildId) != true) { errorcode = -2; goto ChargeValue_Error; }


            //认证
            if (cardos.CardExternalAuthenticate(cardid, 4, DfKey.Key, true) == false) { Console.WriteLine(" DF 下 key 认证出错."); errorcode = -3; goto ChargeValue_Error; }
            else { Console.WriteLine("已经 在DF 下的 key 4 认证通过."); }

            //读卡
            t_GCZ_CardInfo cardInfo = ReadCardShouDian();
            if (cardInfo == null) { errorcode = -4; goto ChargeValue_Error; }

            //计算锁
            byte Lock = (byte)(lockSet == true ? 1 : 0);
            cardInfo.Lock = Lock;

            //写卡
            if (WriteCardShouDian(cardInfo) == false) { errorcode = -5; goto ChargeValue_Error; }
            //再读检查
            t_GCZ_CardInfo rcardInfo = ReadCardShouDian();
            if (rcardInfo == null) { errorcode = -13; goto ChargeValue_Error; }
            else
            {
                if (rcardInfo.Equal(cardInfo))
                {
                    cardos.icardReader.CardReaderCtrl(new String[] { "Buzzer", "2" });
                    Log(this, "msg", "设置锁成功:" + ((Lock == 1) ? "锁定" : "不锁"), null, Rechargeloghandler);
                    string msg = string.Format("CardId:{0:X16}\r\nKey:{1:X16}\r\nLock:{2}\r\nGun:{3:X2}\r\nAddr:{4:X16}\r\nSum:{5:C}", cardInfo.CardID, cardInfo.Key, cardInfo.Lock, cardInfo.GunNum, cardInfo.PileAddr, ((double)(cardInfo.Sum)) / 100);
                    Log(this, "", msg, null, Rechargeloghandler);
                    cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
                    return true;
                }
                else { errorcode = -14; goto ChargeValue_Error; }
            }


        ChargeValue_Error:
            Log(this, "error", "卡锁操作" + errorcode, null, Rechargeloghandler);
            cardos.icardReader.CardReaderCtrl(new string[] { "Antenna", "off" });
            return false;
        }
        #endregion

    }


     
    /// <summary>
    /// Card OS 操作部分
    /// </summary>
    public class CardOS
    {
        public ICardReader icardReader;
        public CardOS(ICardReader icr) { icardReader = icr; }


        #region Cos 协议操作
        /// <summary>
        /// 选择文件
        /// </summary>
        /// <param name="icardReader.readerFd"></param>
        /// <param name="fileId"></param>
        /// <returns></returns>
        public bool CardSelectFile(UInt16 fileId)
        {
            UInt16 lenr = 0;
            Byte[] resp = new Byte[100];
            byte[] cmd = new byte[7] { 0x00, 0xA4, 0x00, 0x00, 0x02, (byte)(fileId >> 8), (byte)(fileId & 0xFF) };
            icardReader.Card_SetNAD(0x15);

            UInt16 result = icardReader.CardApdu((UInt16)cmd.Length, cmd, ref lenr, resp);

            if (result != 0x9000) return false;
            else return true;
        }

        /// <summary>
        /// 卡外部认证
        /// </summary>
        /// <param name="icardReader.readerFd"></param>
        /// <param name="EnDiv">是否使用分散密钥</param>
        /// <param name="CardId">卡序列号 8 bytes</param>
        /// <param name="key">密钥  16 字节</param>
        /// <returns></returns>
        public bool CardExternalAuthenticate(byte[] CardId, Byte keyNumber, Byte[] key, bool EnDiv)
        {

            UInt16 lenr = 0;
            Byte[] resp = new Byte[100];
            byte[] cmd1 = new byte[] { 0x00, 0x84, 0x00, 0x00, 0x08 };
            UInt16 result = 0x9000;
            result = icardReader.CardApdu((UInt16)cmd1.Length, cmd1, ref lenr, resp);//0x9000;// 
            if (result != 0x9000) return false;

            //byte[] random = new byte[]{0xA2, 0x5F, 0xAB, 0xAD ,0x98, 0x46, 0xF3, 0x76};
            //Array.Copy(random, resp, 8);


            //密钥
            byte[] KeySrc = new byte[16];
            byte[] En = new byte[8];


            //////////////////////////////////////////////////////////////////////////
            //算法选择－－〉密钥 由 key分散 产生
            if (EnDiv == true)
            {
                //用 密钥 key 对 CardId 分散 产生 密文 En
                ThreeDes.Diversify(key, CardId, KeySrc);
            }

            //直接使用key作为密钥
            else
            {
                Array.Copy(key, KeySrc, KeySrc.Length);
            }


            //用16字节KeySrc 对 8字节 resp 随机数加密  产生 密文：En
            CRW_Xu_CardReader.TripleDES(1, KeySrc, 8, resp, En);

            Byte[] cmd2 = new Byte[] { 0x00, 0x82, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
            cmd2[3] = keyNumber;
            Array.Copy(En, 0, cmd2, 5, 8);
            result = icardReader.CardApdu( (UInt16)cmd2.Length, cmd2, ref lenr, resp);
            if (result != 0x9000) return false;
            return true;
        }


        /// <summary>
        /// 删除文件
        /// </summary>
        /// <returns></returns>
        public bool CardDeleteFile()
        {
            return false;
        }


        /// <summary>
        /// 删除目录下所有文件
        /// </summary>
        /// <param name="icardReader.readerFd"></param>
        /// <returns></returns>
        public bool CardDeleteDF()
        {

            UInt16 lenr = 0;
            Byte[] resp = new Byte[100];
            byte[] cmd1 = new byte[] { 0x80, 0x0E, 0x00, 0x00, 0x00 };
            UInt16 result = icardReader.CardApdu( (UInt16)cmd1.Length, cmd1, ref lenr, resp);
            if (result != 0x9000) return false;
            return true;
        }



        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="icardReader.readerFd"></param>
        /// <returns></returns>
        public bool CardCreateFile(DFInfo info)
        {

            UInt16 lenr = 0;
            Byte[] resp = new Byte[100];
            byte[] infodata = info.FileInfo;
            byte[] cmd = new byte[5 + infodata.Length];


            //////////////////////////////////////////////////////////////////////////
            cmd[0] = 0x80; cmd[1] = 0xE0;
            cmd[2] = (byte)info.FileId[0];
            cmd[3] = (byte)(info.FileId[1]);
            cmd[4] = (byte)infodata.Length;
            Array.Copy(infodata, 0, cmd, 5, infodata.Length);

            UInt16 result = icardReader.CardApdu( (UInt16)cmd.Length, cmd, ref lenr, resp);
            if (result != 0x9000) return false;
            return true;

        }



        /// <summary>
        /// 写密钥 
        /// </summary>
        /// <param name="icardReader.readerFd"></param>
        /// <returns></returns>
        public bool CardWriteKey(byte KeyId, KeyInfo keyInfo)
        {

            UInt16 lenr = 0;
            Byte[] resp = new Byte[100];
            byte[] cmd = new byte[] { 0x80, 0xD4, 0x01, 0x00, 0x15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


            //////////////////////////////////////////////////////////////////////////
            cmd[3] = (KeyId);

            Array.Copy(keyInfo.ToBytes(), 0, cmd, 5, 21);

            UInt16 result = icardReader.CardApdu( (UInt16)cmd.Length, cmd, ref lenr, resp);
            if (result != 0x9000) return false;
            return true;
        }


        /// <summary>
        ///  写 二进制 文件  <200
        /// </summary>
        /// <param name="FileId"> 文件名</param>
        /// <param name="offset">偏移</param>
        /// <param name="buffer">写入的数据</param>
        /// <param name="len">写入数据的长度  <200</param>
        /// <returns>true: 成功  false :失败</returns>
        public bool CardWriteBinFile(UInt16 FileId, byte offset, byte[] buffer, byte len) {

            byte[] Comd = new byte[250];
            byte[] RecMsg = new byte[50];
            UInt16 rlen = 0;

            Comd[0]=0x00;Comd[1]=0xD6;Comd[2]=(byte)(0x80|(FileId&0x1F));
            Comd[3] = offset;
            Comd[4]= len;
            Array.Copy(buffer,0,Comd,5,len);

            UInt16 r = icardReader.CardApdu((UInt16)(len+5),Comd,ref rlen,RecMsg);

            if (r != 0x9000)
            {
                return false;
            }
            else return true;
        }


        /// <summary>
        /// 读十进制文件
        /// </summary>
        /// <param name="FileId"></param>
        /// <param name="offsest"></param>
        /// <param name="buffer"></param>
        /// <param name="wantlen"></param>
        /// <returns>返回字节长度, -1 ：不成功   -2:长度很小</returns>
        public int CardReadBInFile(UInt16 FileId, byte offset, byte[] buffer, byte wantlen)
        {

            byte[] Comd = new byte[] { 0x00, 0xB0, 0x80, 0x00, 0x00 };
            byte[] RecMsg = new byte[250];
            UInt16 rlen = 0;

            Comd[2] |= (byte)((FileId & 0x1F));
            Comd[3] = offset;
            Comd[4] = wantlen;
            UInt16 r = icardReader.CardApdu((UInt16)(Comd.Length), Comd, ref rlen, RecMsg);

            if (r != 0x9000)
            {
                return -1;
            }
            else {
                int getlen =  rlen>wantlen?wantlen:rlen;
                if (buffer != null) Array.Copy(RecMsg, 0, buffer, 0,getlen);
                return  getlen;
            }
        }

        #endregion
    
        

    }

}
